import _ from 'lodash'
import {article, section} from './lablog.js'
import fs from 'fs'
import chalk from 'chalk'


article("容器上的 of 方法，不是用来避免使用 new 关键字的，而是用来将值放到 默认最小化上下文中的。")
section("of 并没有真正地取代构造器，它是一个我们称之为 pointed 的重要接口的一部分")
section("pointed functor 是实现了 of 方法的 functor")
section("这里的关键是将任意值丢到容器里然后开始到处使用 map 的能力")

/* Util Begin ---------------------------- */

const Maybe = function(x) {
    this.__value = x
}
Maybe.of = function(x) {
    return new Maybe(x)
}
Maybe.prototype.isNothing = function() {
    return (this.__value === null || this.__value === undefined)
}
Maybe.prototype.map = function(f) {
    return this.isNothing() ? Maybe.of(null) : Maybe.of(f(this.__value))
}

const add = _.curry(function(x, y) {return x + y})

console.log("Maybe.of(123).map(add(1))", Maybe.of(123).map(add(1)))

const IO = function(f) {
    this.__value = f
}
IO.of = function(x) {
    return new IO(function() {
        return x
    })
}
IO.prototype.map = function(f) {
    return new IO(_.flowRight(f, this.__value))
}

const map = _.curry(function(f, functor) {
    return functor.map(f)
})

/* Util End --------------------- */

const readFile = function(fileName) {
    return new IO(function() {
        return fs.readFileSync(fileName, 'utf-8')
    })
}

const print = function(x) {
    return new IO(function() {
        console.log(x)
        return x
    })
}

const cat = _.flowRight(map(print), readFile)

console.group(chalk.bgBlue("Basic test"))
console.log(cat("README.md"))
// console.log(cat("README.md").__value.toString())
console.log(cat(".git").__value().__value())
console.groupEnd()

const safeProp = _.curry(function(x, obj) {
    // console.log("safe prop", obj)
    return new Maybe(obj[x])
})
const safeHead = safeProp(0)
const firstAddressStreet = _.flowRight(
    map(map(safeProp('street'))),
    map(safeHead),
    safeProp('addresses')
)
console.group(chalk.bgBlue("begin execute"))
const addressInfo = {
    addresses: [
        {street: {name: 'Mul', number: 22}, postcode: 'ww'}
    ]
}
const result = firstAddressStreet(addressInfo)

console.log(safeProp('addresses')(addressInfo))
console.log(_.flowRight(map(safeHead), safeProp('addresses'))(addressInfo))
console.log(result)
console.log(result.__value.__value.__value)
console.groupEnd("execute end")


Maybe.prototype.join = function() {
    return this.isNothing() ? Maybe.of(null) : this.__value
}

console.group(chalk.bgBlueBright("Basic join begin"))
const mmo = Maybe.of(Maybe.of("nunchecks"))
console.log(mmo)
console.log(mmo.join())
console.groupEnd()


const join = function(mma) {return mma.join()}
const firstAddressStreetWithJoin = _.flowRight(
    join,
    map(safeProp('street')),
    join,
    map(safeHead),
    safeProp('addresses')
)
console.log(firstAddressStreetWithJoin(addressInfo))
section("如果有两层相同类型的嵌套，就使用 join 将它们压扁到一起。")
section("monad 是可以变扁(flatten)的 pointed functor")
 
